#!/usr/bin/env python

"""Test PySlip layer resource files."""


import os
import tempfile
import json
import unittest

import pyslip


######
# Various constants
######

class Test_Resource(unittest.TestCase):

    def test_resource_load(self):
        """Test the loading of a resource."""

        # create temporary filename
        (fd, filename) = tempfile.mkstemp(prefix='test_resource_')
        os.close(fd)

        # create known layer JSON file
        example_layer = [[1,2,'text',{}], [3,4,'more',{}]]
        layer_dict = {"test":[pyslip.PySlip.TypeText, example_layer]}

        with open(filename, 'wb') as fp:
            json.dump(layer_dict, fp, ensure_ascii=False,
                      indent=2, separators=(',', ':'))

        self.failUnlessRaises(IOError, pyslip.Resource, '/tmpx/no_such_file')

        # read the resource file
        layers = pyslip.Resource(filename)
        self.failUnless(isinstance(layers, pyslip.Resource),
                        'layer resource is not a Resource')

        # check that Resource attributes are as expected
        msg = ('Resource should have filename=%s, got %s'
               % (filename, str(layers.filename)))
        self.failUnlessEqual(layers.filename, filename, msg)

        layer = layers.GetLayer('no such layer')
        self.failUnless(layer is None,
                        'Attempt to get non-existent layer returned layer?')

        layer = layers.GetLayer('test')
        self.failUnless(isinstance(layer, list),
                        'layer resource is not a list')

        self.failUnless(len(layer) == 2, 'layer must be [<type>, <data>]')

        (layer_type, layer_data) = layer
        self.failUnless(isinstance(layer_type, int), '<type> must be integer')
        self.failUnless(layer_type == pyslip.PySlip.TypeText,
                        '<type> must be pyslip.PySlip.TypeText (%d)'
                        % pyslip.PySlip.TypeText)

        self.failUnlessEqual(example_layer, layer_data)

        # delete the temporary file
        os.remove(filename)

    def test_resource_write_simple(self):
        """Test the writing of a resource."""

        # create temporary filename
        (fd, filename) = tempfile.mkstemp(prefix='test_resource_')
        os.close(fd)

        # create known layer JSON file
        example_layer = [[1,2,'text',{}], [3,4,'more',{}]]
        layer_dict = {"test":[pyslip.PySlip.TypeText, example_layer]}

        with open(filename, 'wb') as fp:
            json.dump(layer_dict, fp, ensure_ascii=False,
                      indent=2, separators=(',', ':'))

        # read the known layer
        layers = pyslip.Resource(filename)
        self.failUnless(isinstance(layers, pyslip.Resource),
                        'layer resource is not a Resource')

        (_, layer) = layers.GetLayer('test')

        # create new empty Resource, add layer, write out
        layers = pyslip.Resource()
        layers.AddLayer('test2', pyslip.PySlip.TypeText, layer)
        (fd, filename_out) = tempfile.mkstemp(prefix='test_resource_')
        os.close(fd)
        layers.Write(filename_out)

        # read in the layer just written, make sure as expected
        layers = pyslip.Resource(filename_out)
        (layer_type, layer_data) = layers.GetLayer('test2')
        msg = "Didn't read what was written"
        self.failUnlessEqual(layer_type, pyslip.PySlip.TypeText, msg)
        self.failUnlessEqual(layer_data, example_layer, msg)

        # delete the temporary files
        os.remove(filename)
        os.remove(filename_out)

    def test_resource_write(self):
        """Test the writing of a resource with many layers."""

        # create temporary filename
        (fd, filename) = tempfile.mkstemp(prefix='test_resource_')
        os.close(fd)

        # create known layers JSON file
        example_layer = [[1,2,'text',{}], [3,4,'more',{'size':100,'a':'b'}]]
        example_layer2 = [[5,6,'text2',{}], [7,8,'more text',{'colour':'red'}]]
        example_layer3 = [[9,10,'text3',{'alpha':'bravo'}], [11,12,'less text',{}]]
        layer_dict = {"test":[pyslip.PySlip.TypeText, example_layer],
                      "test2":[pyslip.PySlip.TypeText, example_layer2],
                      "test3":[pyslip.PySlip.TypeText, example_layer3],
                      }

        with open(filename, 'wb') as fp:
            json.dump(layer_dict, fp, ensure_ascii=False,
                      indent=2, separators=(',', ':'))

        # read the known layers
        layers = pyslip.Resource(filename)
        self.failUnless(isinstance(layers, pyslip.Resource),
                        'layer resource is not a Resource')

        (_, layer) = layers.GetLayer('test')
        (_, layer2) = layers.GetLayer('test2')
        (_, layer3) = layers.GetLayer('test3')

        # create new empty Resource, add layer, write out
        layers = pyslip.Resource()
        layers.AddLayer('layer', pyslip.PySlip.TypeText, layer)
        layers.AddLayer('layer2', pyslip.PySlip.TypeText, layer2)
        layers.AddLayer('layer3', pyslip.PySlip.TypeText, layer3)
        (fd, filename_out) = tempfile.mkstemp(prefix='test_resource_')
        os.close(fd)
        layers.Write(filename_out)

        # read in the layers just written, make sure as expected
        layers = pyslip.Resource(filename_out)
        (layer_type, layer_data) = layers.GetLayer('layer')
        (layer_type2, layer_data2) = layers.GetLayer('layer2')
        (layer_type3, layer_data3) = layers.GetLayer('layer3')
        msg = "Didn't read what was written"
        self.failUnlessEqual(layer_type, pyslip.PySlip.TypeText, msg)
        self.failUnlessEqual(layer_data, example_layer, msg)
        self.failUnlessEqual(layer_type2, pyslip.PySlip.TypeText, msg)
        self.failUnlessEqual(layer_data2, example_layer2, msg)
        self.failUnlessEqual(layer_type3, pyslip.PySlip.TypeText, msg)
        self.failUnlessEqual(layer_data3, example_layer3, msg)

        # delete the temporary files
        os.remove(filename)
        os.remove(filename_out)

    def test_resource_delete(self):
        """Test the deleting of a layer within a resource."""

        # create known layers data
        example_layer = [[1,2,'text',{}], [3,4,'more',{'size':100,'a':'b'}]]
        example_layer2 = [[5,6,'text2',{}], [7,8,'more text',{'colour':'red'}]]
        example_layer3 = [[9,10,'text3',{'alpha':'bravo'}], [11,12,'less text',{}]]

        # create new empty Resource, add layers
        layers = pyslip.Resource()
        layers.AddLayer('layer', pyslip.PySlip.TypeText, example_layer)
        layers.AddLayer('layer2', pyslip.PySlip.TypeText, example_layer2)
        layers.AddLayer('layer3', pyslip.PySlip.TypeText, example_layer3)

        # check that Resource attributes are as expected
        msg = ('Empty resource should have no filename, got %s'
               % str(layers.filename))
        self.failUnless(layers.filename is None, msg)

        # check layers length, delete layers one by one
        len_layers = len(layers)
        msg = 'len(layers) returned %d, expected 3' % len_layers
        self.failUnlessEqual(len_layers, 3, msg)

        del_layer = 'layer2'
        expected_len = 2
        layers.DeleteLayer(del_layer)
        len_layers = len(layers)
        msg = 'len(layers) returned %d, expected %d' % (len_layers, expected_len)
        self.failUnlessEqual(len_layers, expected_len, msg)
        layer = layers.GetLayer(del_layer)
        self.failUnless(layer is None,
                        'Attempt to get deleted layer %s returned layer?' % del_layer)

        del_layer = 'layer'
        expected_len = 1
        layers.DeleteLayer(del_layer)
        len_layers = len(layers)
        msg = 'len(layers) returned %d, expected %d' % (len_layers, expected_len)
        self.failUnlessEqual(len_layers, expected_len, msg)
        layer = layers.GetLayer(del_layer)
        self.failUnless(layer is None,
                        'Attempt to get deleted layer %s returned layer?' % del_layer)

        del_layer = 'layer3'
        expected_len = 0
        layers.DeleteLayer(del_layer)
        len_layers = len(layers)
        msg = 'len(layers) returned %d, expected %d' % (len_layers, expected_len)
        self.failUnlessEqual(len_layers, expected_len, msg)
        layer = layers.GetLayer(del_layer)
        self.failUnless(layer is None,
                        'Attempt to get deleted layer %s returned layer?' % del_layer)

        # should not error
        layers.DeleteLayer('no such layer')


################################################################################

if __name__ == '__main__':
    suite = unittest.makeSuite(Test_Resource,'test')
    runner = unittest.TextTestRunner()
    runner.run(suite)
